home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / SecureRandom.java < prev    next >
Text File  |  1998-09-22  |  10KB  |  297 lines

  1. /*
  2.  * @(#)SecureRandom.java    1.19 98/08/06
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  * 
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.security;
  16.  
  17. import java.util.*;
  18.  
  19. /**
  20.  * <p>This class provides a crytpographically strong pseudo-random number
  21.  * generator based on the SHA-1 hash algorithm.
  22.  *
  23.  * <p>The calls inherited from Random will be implemented in terms of the
  24.  * strengthened functionality.
  25.  *
  26.  * @see java.util.Random
  27.  * 
  28.  * @version 1.2 96/09/15
  29.  * @author Benjamin Renaud
  30.  * @author Josh Bloch 
  31.  * @author Gadi Guy
  32.  */
  33.  
  34. public class SecureRandom extends Random {
  35.  
  36.     /**
  37.      * Used by the empty constructor to seed the SecureRandom under
  38.      * construction.
  39.      */
  40.     private static SecureRandom seeder;
  41.     private static final int DIGEST_SIZE = 20;
  42.     private transient MessageDigest digest;
  43.     private byte[] state;
  44.     private byte[] remainder;
  45.     private int remCount;
  46.  
  47.     /**
  48.      * This empty constructor automatically seeds the generator.  We attempt
  49.      * to provide sufficient seed bytes to completely randomize the internal
  50.      * state of the generator (20 bytes).  Note, however, that our seed
  51.      * generation algorithm has not been thoroughly studied or widely deployed.
  52.      * 
  53.      * <p>The first time this constructor is called in a given Virtual Machine,
  54.      * it may take several seconds of CPU time to seed the generator, depending
  55.      * on the underlying hardware.  Successive calls run quickly because they
  56.      * rely on the same (internal) pseudo-random number generator for their
  57.      * seed bits.
  58.      *
  59.      * <p>The seeding procedure implemented by this constructor ensures that
  60.      * the sequence of pseudo-random bytes produced by each SecureRandom 
  61.      * instance yields no useful information about the byte-sequence produced
  62.      * by any other instance.  If however, the user wishes to produce multiple 
  63.      * instances with truly unrelated seeds, the following code yields
  64.      * the desired result (at substantial CPU cost per instance!):<p>
  65.      *
  66.      * <pre>
  67.      * SecureRandom rnd = new SecureRandom(SecureRandom.getSeed(20));
  68.      * </pre>
  69.      */
  70.     public SecureRandom() {
  71.     this(nextSeed());
  72.     }
  73.  
  74.     /**
  75.      * This call, used exclusively by the empty constructor, returns 20 seed
  76.      * bytes to seed the SecureRandom instance under construction.  The first
  77.      * time this method is called, creates a class-wide generator-generator.
  78.      * This involves generating 20 "real-random" bytes with getSeed, which is
  79.      * very time consuming!
  80.      */
  81.     private synchronized static byte[] nextSeed() {
  82.     if (seeder == null) {
  83.         seeder = new SecureRandom(getSeed(20));
  84.         seeder.setSeed(SeedGenerator.getSystemEntropy());
  85.     }
  86.  
  87.     byte seed[] = new byte[20];
  88.     seeder.nextBytes(seed);
  89.     return seed;
  90.     }
  91.  
  92.  
  93.     /**
  94.      * This constructor uses a user-provided seed in preference to the 
  95.      * self-seeding algorithm referred to in the empty constructor 
  96.      * description. It may be preferable to the empty constructor if the 
  97.      * caller has access to high-quality random bytes from some physical 
  98.      * device (for example, a radiation detector or a noisy diode).
  99.      * 
  100.      * @param seed the seed.
  101.      */
  102.     public SecureRandom(byte seed[]) {
  103.     /*
  104.      * This call to our superclass constructor will result in a call
  105.      * to our own setSeed method, which will return immediately when
  106.      * it is passed zero.
  107.      */
  108.     super(0);
  109.  
  110.     try {
  111.         digest = MessageDigest.getInstance("SHA");
  112.     } catch (NoSuchAlgorithmException e) {
  113.         throw new InternalError("internal error: SHA-1 not available.");
  114.     }
  115.  
  116.     setSeed(seed);
  117.     }
  118.  
  119.     /**
  120.      * Reseeds this random object. The given seed supplements, rather than
  121.      * replaces, the existing seed. Thus, repeated calls are guaranteed
  122.      * never to reduce randomness.
  123.      *
  124.      * @param seed the seed.
  125.      */
  126.     synchronized public void setSeed(byte[] seed) {
  127.     if (state != null) {
  128.         digest.update(state);
  129.         for (int i = 0; i < state.length; i++)
  130.         state[i] = 0;
  131.     }
  132.     state = digest.digest(seed);
  133.     }
  134.  
  135.     /**
  136.      * Reseeds this random object, using the eight bytes contained 
  137.      * in the given <code>long seed</code>. The given seed supplements, 
  138.      * rather than replaces, the existing seed. Thus, repeated calls 
  139.      * are guaranteed never to reduce randomness. 
  140.      * 
  141.      * <p>This method is defined for compatibility with 
  142.      * <code>java.util.Random</code>.
  143.      *
  144.      * @param seed the seed.
  145.      */
  146.     public void setSeed(long seed) {
  147.     /* 
  148.      * Ignore call from super constructor (as well as any other calls
  149.      * unfortunate enough to be passing 0).  It's critical that we
  150.      * ignore call from superclass constructor, as digest has not
  151.      * yet been initialized at that point.
  152.      */
  153.     if (seed != 0)
  154.         setSeed(longToByteArray(seed));
  155.     }
  156.  
  157.     private static void updateState(byte[] state, byte[] output) {
  158.     int last = 1;
  159.     int v = 0;
  160.     byte t = 0;
  161.     boolean zf = false;
  162.  
  163.     // state(n + 1) = (state(n) + output(n) + 1) % 2^160;
  164.     for (int i = 0; i < state.length; i++) {
  165.         // Add two bytes
  166.         v = (int)state[i] + (int)output[i] + last;
  167.         // Result is lower 8 bits
  168.         t = (byte)v;
  169.         // Store result. Check for state collision.
  170.         zf = zf | (state[i] != t);
  171.         state[i] = t;
  172.         // High 8 bits are carry. Store for next iteration.
  173.         last = v >> 8;
  174.     }
  175.  
  176.     // Make sure at least one bit changes!
  177.     if (!zf)
  178.        state[0]++;
  179.     }
  180.  
  181.     /**
  182.      * Generates a user-specified number of random bytes.  This method is
  183.      * used as the basis of all random entities returned by this class
  184.      * (except seed bytes).  Thus, it may be overridden to change the
  185.      * behavior of the class.
  186.      * 
  187.      * @param bytes the array to be filled in with random bytes.
  188.      */
  189.  
  190.     synchronized public void nextBytes(byte[] result) {
  191.     int index = 0;
  192.     int todo;
  193.     byte[] output = remainder;
  194.  
  195.     // Use remainder from last time
  196.     int r = remCount;
  197.     if (r > 0) {
  198.         // How many bytes?
  199.         todo = (result.length - index) < (DIGEST_SIZE - r) ?
  200.             (result.length - index) : (DIGEST_SIZE - r);
  201.         // Copy the bytes, zero the buffer
  202.         for (int i = 0; i < todo; i++) {
  203.         result[i] = output[r];
  204.         output[r++] = 0;
  205.         }
  206.         remCount += todo;
  207.         index += todo;
  208.     }
  209.  
  210.     // If we need more bytes, make them.
  211.     while (index < result.length) {
  212.         // Step the state
  213.         digest.update(state);
  214.         output = digest.digest();
  215.         updateState(state, output);
  216.  
  217.         // How many bytes?
  218.         todo = (result.length - index) > DIGEST_SIZE ?
  219.         DIGEST_SIZE : result.length - index;
  220.         // Copy the bytes, zero the buffer
  221.         for (int i = 0; i < todo; i++) {
  222.         result[index++] = output[i];
  223.         output[i] = 0;
  224.         }
  225.         remCount += todo;
  226.     }
  227.  
  228.     // Store remainder for next time
  229.     remainder = output;
  230.     remCount %= DIGEST_SIZE;
  231.     }
  232.  
  233.     /**
  234.      * Generates an integer containing the user-specified number of
  235.      * pseudo-random bits (right justified, with leading zeros).  This
  236.      * method overrides a <code>java.util.Random</code> method, and serves 
  237.      * to provide a source of random bits to all of the methods inherited 
  238.      * from that class (for example, <code>nextInt</code>, 
  239.      * <code>nextLong</code>, and <code>nextFloat</code>).
  240.      *
  241.      * @param numBits number of pseudo-random bits to be generated, where 
  242.      * 0 <= <code>numBits</code> <= 32.
  243.      */
  244.     final protected int next(int numBits) {
  245.     int numBytes = (numBits+7)/8;
  246.     byte b[] = new byte[numBytes];
  247.         int next = 0;
  248.  
  249.     nextBytes(b);
  250.     for (int i=0; i<numBytes; i++)
  251.         next = (next << 8) + (b[i] & 0xFF);
  252.  
  253.         return next >>> (numBytes*8 - numBits);
  254.     }
  255.  
  256.     /**
  257.      * Returns the given number of seed bytes, computed using the seed
  258.      * generation algorithm that this class uses to seed itself.  This
  259.      * call may be used to seed other random number generators.  While
  260.      * we attempt to return a "truly random" sequence of bytes, we do not 
  261.      * know exactly how random the bytes returned by this call are.  (See 
  262.      * the empty constructor <a href = "#SecureRandom">SecureRandom</a>
  263.      * for a brief description of the underlying algorithm.)
  264.      * The prudent user will err on the side of caution and get extra
  265.      * seed bytes, although it should be noted that seed generation is
  266.      * somewhat costly.
  267.      *
  268.      * @param numBytes the number of seed bytes to generate.
  269.      * 
  270.      * @return the seed bytes.
  271.      */
  272.      public static byte[] getSeed(int numBytes) {
  273.      byte[] retVal = new byte[numBytes];
  274.  
  275.      for (int i=0; i<numBytes; i++)
  276.          retVal[i] = (byte) SeedGenerator.getByte();
  277.  
  278.      return retVal;
  279.      }
  280.  
  281.  
  282.     /**
  283.      * Helper function to convert a long into a byte array (least significant
  284.      * byte first).
  285.      */
  286.     private static byte[] longToByteArray(long l) {
  287.     byte[] retVal = new byte[8];
  288.  
  289.     for (int i=0; i<8; i++) {
  290.         retVal[i] = (byte) l;
  291.         l >>= 8;
  292.     }
  293.  
  294.     return retVal;
  295.     }
  296. }
  297.